//C19:19.5
// Listing -19.5 Passing Template Objects to and from Functions
#include <iostream>
#include <ostream>
using namespace std;

const int DefaultSize = 10;

// A trival class for adding to arrays
class Animal
{
    public:
        Animal(int);
        Animal();
        ~Animal();
        int GetWeight() const { return itsWeight; }
        void SetWeight(int theWeight) { itsWeight = itsWeight; }
        friend ostream&
        operator<<(ostream&, const Animal&);
    private:
        int itsWeight;
};

// extraction operator for printing animals
ostream& operator<<(ostream& theStream, const Animal& theAnimal)
{
    theStream << theAnimal.GetWeight();
    return theStream;
}

Animal::Animal(int weight)
:itsWeight(weight) 
{
    // cout << "Animal(int)" << endl;
}

Animal::Animal() :itsWeight(0)
{
    // cout << "Animal()" << endl;
}

Animal::~Animal()
{
    // cout << "Destroyed an animal..." << endl;
}

template<class T>
class Array
{
    public:
        Array(int itsSize = DefaultSize);
        Array(const Array &rhs);
        ~Array() { delete[] pType; }

        Array& operator=(const Array&);
        T& operator[](int offSet) {return pType[offSet]; }
        const T& operator[](int offSet) const
        {
            return pType[offSet];
        }

        int GetSize() const { return itsSize; }
        // friend function
        // template <class T>
        friend ostream& operator<<(ostream&, const Array<T>&);
    private:
        T *pType;
        int itsSize;    
};

template<class T>
ostream& operator<<(ostream& output, const Array<T>& theArray)
{
    for (int i = 0; i < theArray.itsSize; i++)
    {
        output << "[" << i << "] " << theArray[i] << endl;
    }
    return output;
}

// implementationis follow...
// implement the Constructor
template<class T>
Array<T>::Array(int size)
: itsSize(size)
{
    pType = new T[size];
    for (int i = 0; i < size; i++)
    {
        pType[i] = 0;
    }
}

template<class T>
Array<T>::Array(const Array &rhs)
{
    itsSize = rhs.GetSize();
    pType = new T[itsSize];
    for (int i = 0; i < itsSize; i++)
    {
        pType[i] = rhs[i];
    }
}

void IntFillFunction(Array<int>& theArray);
void AnimalFillFunction(Array<Animal>& theArray);

int main(void)
{
    Array<int> intArray;
    Array<Animal> ainmalArray;
    IntFillFunction(intArray);
    AnimalFillFunction(ainmalArray);
    cout << "iniArray...\n" << intArray;
    cout << "\nanimalArray...\n" << ainmalArray << endl;
}

void IntFillFunction(Array<int>& theArray)
{
    bool Stop = false;
    int offset, value;
    while (Stop == false)
    {
        cout << "Enter an offset (0-9) ";
        cout << "and a value. (-1 to stop):";
        cin >> offset >> value;
        if (offset < 0)
        {
            break;
        }

        if (offset > 9)
        {
            cout << "***Please use values between 0 and 9.***\n";
            continue;
        }

        theArray[offset] = value;
    }
}

void AnimalFillFunction(Array<Animal>& theArray)
{
    Animal *pAnimal;
    for (int i = 0; i < theArray.GetSize(); i++)
    {
        pAnimal = new Animal;
        pAnimal->SetWeight(i * 100);
        theArray[i] = *pAnimal;
        delete pAnimal;
    }
}



